package com.hice.demo.sbdbra.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class HttpUtils
{
  private static CloseableHttpClient httpClient;
  private static final String ENCODEING = "UTF-8";
  private static Logger log = LoggerFactory.getLogger(HttpUtils.class);

  public static String doGet(String url, Map<String, Object> headers, Map<String, Object> params)
  {
    String result = null;
    HttpGet httpGet = null;
    try
    {
      StringBuffer param;
      if (params != null) {
        param = new StringBuffer();
        for (String key : params.keySet()) {
          if (param.length() == 0)
            param.append("?");
          else
            param.append("&");
          param.append(key).append("=").append(URLEncoder.encode(params.get(key).toString(), "UTF-8"));
        }
        url = url + param;
      }

      httpGet = new HttpGet(url);

      if (headers != null) {
        for (String key : headers.keySet()) {
          httpGet.setHeader(key, headers.get(key).toString());
        }
      }

      HttpResponse response = httpClient.execute(httpGet);
      int statusCode = response.getStatusLine().getStatusCode();

      if (statusCode == 200) {
        HttpEntity entity = response.getEntity();
        if (entity != null)
          result = EntityUtils.toString(entity, "UTF-8");
      }
    }
    catch (IOException e) {
      log.error("HttpClient: doGet error.url=" + url + ",headers=" + headers + ",params=" + params, e);
    } finally {
      if (httpGet != null) {
        httpGet.releaseConnection();
      }
    }

    return result;
  }

  public static byte[] doGetForBytes(String url, Map<String, Object> headers, Map<String, Object> params)
  {
    byte[] result = null;
    HttpGet httpGet = null;
    try
    {
      StringBuffer param;
      if (params != null) {
        param = new StringBuffer();
        for (String key : params.keySet()) {
          if (param.length() == 0)
            param.append("?");
          else
            param.append("&");
          param.append(key).append("=").append(URLEncoder.encode(params.get(key).toString(), "UTF-8"));
        }
        url = url + param;
      }

      httpGet = new HttpGet(url);

      if (headers != null) {
        for (String key : headers.keySet()) {
          httpGet.setHeader(key, headers.get(key).toString());
        }
      }

      HttpResponse response = httpClient.execute(httpGet);
      int statusCode = response.getStatusLine().getStatusCode();

      if (statusCode == 200) {
        HttpEntity entity = response.getEntity();
        if (entity != null)
          result = EntityUtils.toByteArray(entity);
      }
    }
    catch (IOException e) {
      log.error("HttpClient: doGet error.url=" + url + ",headers=" + headers + ",params=" + params, e);
    } finally {
      if (httpGet != null) {
        httpGet.releaseConnection();
      }
    }

    return result;
  }

  public static String doPost(String url, Map<String, Object> headers, Map<String, Object> params)
  {
    try
    {
      HttpEntity entity = null;
      if (params != null) {
        List pairList = new ArrayList();
        for (Entry entry : params.entrySet()) {
          String value = "";
          if (CommonFuntions.isNotEmptyObject(entry.getValue())) {
            value = entry.getValue() + "";
          }
          NameValuePair pair = new BasicNameValuePair((String)entry.getKey(), value);
          pairList.add(pair);
        }
        entity = new UrlEncodedFormEntity(pairList);
      }
      return doPost(url, headers, entity);
    } catch (Exception e) {
      log.error("HttpClient: doPost error.url=" + url + ",headers=" + headers + ",params=" + params, e);
    }
    return null;
  }

  public static String doPost(String url, Map<String, Object> headers, String str)
  {
    try
    {
      HttpEntity entity = null;
      if (StringUtils.isNotBlank(str)) {
        entity = new StringEntity(str.toString(), "UTF-8");
      }
      return doPost(url, headers, entity);
    } catch (Exception e) {
      log.error("HttpClient: doPost error.url=" + url + ",headers=" + headers + ",str=" + str, e);
    }
    return null;
  }

  private static String doPost(String url, Map<String, Object> headers, HttpEntity requestEntity)
    throws Exception
  {
    HttpPost httpPost = new HttpPost(url);
    try
    {
      if (requestEntity != null) {
        httpPost.setEntity(requestEntity);
      }

      if (headers != null) {
        for (String key : headers.keySet()) {
          httpPost.setHeader(key, headers.get(key).toString());
        }
      }

      Object response = httpClient.execute(httpPost);
      int statusCode = ((HttpResponse)response).getStatusLine().getStatusCode();

      if (statusCode == 200) {
        HttpEntity entity = ((HttpResponse)response).getEntity();
        if (entity != null) {
          String str1 = EntityUtils.toString(entity, "UTF-8");
          return str1;
        }
      } else {
        log.error("HttpClient: doPost error.statusCode=" + statusCode + "url=" + url + ",headers=" + headers + ",requestEntity=" + requestEntity);
      }
    }
    finally {
      httpPost.releaseConnection();
    }

    return (String)null;
  }

  private static SSLConnectionSocketFactory createSSLConnSocketFactory()
  {
    SSLConnectionSocketFactory sslsf = null;
    try {
      SSLContext ctx = SSLContext.getInstance("TLS");

      X509TrustManager tm = new X509TrustManager()
      {
        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException
        {
        }

        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException
        {
        }

        public X509Certificate[] getAcceptedIssuers()
        {
          return null;
        }
      };
      ctx.init(null, new TrustManager[] { tm }, null);
      sslsf = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
    } catch (Exception e) {
      log.error("HttpClient: create SSL socket factory error.", e);
    }

    return sslsf;
  }

  static
  {
    RequestConfig requestConfig = RequestConfig.custom()
      .setConnectTimeout(30000)
      .setSocketTimeout(50000)
      .setConnectionRequestTimeout(50000)
      .setAuthenticationEnabled(true)
      .setExpectContinueEnabled(true)
      .setTargetPreferredAuthSchemes(Arrays.asList(new String[] { "NTLM", "Digest" }))
      .setProxyPreferredAuthSchemes(Arrays.asList(new String[] { "Basic" }))
      .build();

    Registry socketFactoryRegistry = RegistryBuilder.create()
      .register("http", PlainConnectionSocketFactory.INSTANCE)
      .register("https", 
      createSSLConnSocketFactory()).build();

    PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    connManager.setMaxTotal(50);
    connManager.setDefaultMaxPerRoute(50);

    httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig)
      .build();
  }
}